package cn.tedu.reflection;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**本类用于测试暴力反射*/
public class TestReflect2 {
    /**1.通过暴力反射获取与操作属性*/
    @Test
    public void getFie2() throws Exception {
        //获取字节码对象
        Class<?> clazz = Person.class;
        //获取指定私有属性,方法参数传入的就是指定属性的名字，而不是类型，因为类型可以重复，属性名不会重复
        Field field = clazz.getDeclaredField("name");
        //打印查看刚刚获取到的属性对象
        System.out.println(field);
        //根据刚刚获取到的属性对象，进一步查看属性的各种信息
        System.out.println(field.getType());
        System.out.println(field.getType().getName());

        Field field1 = clazz.getDeclaredField("age");
        System.out.println(field1);
        System.out.println(field1.getType());
        System.out.println(field1.getType().getName());

        //设置属性的值
        //1.需要指定到底是给哪个对象的name属性设置值，没有对象就创建对象
        Object p1 = clazz.newInstance();//利用反射，触发无参构造创建对象
        /**暴力反射，需要设置私有可见的权限！！！*/
        field.setAccessible(true);
        //通过字段对象Field给刚刚创建好的对象p1设置属性值
        //field.set(o,n); o是指具体给哪个对象设置值，n是指具体的值是什么
        field.set(p1,"海绵宝宝");
        //field.get(o); o是指具体查看哪个对象的name属性值
        System.out.println(field.get(p1));
    }
    //定义单元测试方法，利用暴力反射操作Person类中的私有属性age
    @Test
    public void getFie3() throws Exception {
        Class<?> clazz = Person.class;
        Field field = clazz.getDeclaredField("age");
        System.out.println(field);
        System.out.println(field.getType());
        System.out.println(field.getType().getName());

        Object p1 = clazz.newInstance();
        field.setAccessible(true);
        field.set(p1,66);
        System.out.println(field.get(p1));
        //全参构造
        Constructor<?> c = clazz.getConstructor(String.class, int.class);
        Object p = c.newInstance("张三", 5);
        System.out.println(p);
    }

    /**2.通过暴力反射获取与使用方法*/
    @Test
    public void getFunction2() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //获取字节码对象
        Class<?> clazz = Person.class;
        //通过暴力反射获取指定的私有方法
        /**getDeclaredMethod(n,x,y,z...)
         * n：要获取的指定方法的方法名
         * x,y,z...可变参数，是指指定方法的参数类型，注意传入的是字节码对象*/
        Method method = clazz.getDeclaredMethod("save", int.class, String.class);
//        System.out.println(method);//证明已获取到方法
        /**执行私有方法*/
        //暴力反射需要设置权限
        method.setAccessible(true);
        //通过反射创建对象
        Object p3 = clazz.newInstance();
        /**invoke(o,x,y,z...)表示通过反射执行方法
         * o：代表要给哪个对象执行上面获取到的save()
         * x,y,z...执行save()时需要传入的参数*/
        method.invoke(p3,999,"感冒灵");
    }
    @Test
    public void getFunction3() throws Exception {
        Class<?> clazz = Person.class;
        Method method = clazz.getDeclaredMethod("update");
        Object p4 = clazz.newInstance();
        method.setAccessible(true);
        method.invoke(p4);
    }

    @Test
    public void getFunction4() throws Exception {
        Class<?> clazz = Person.class;
        Method method = clazz.getDeclaredMethod("add", String.class);
        method.setAccessible(true);
        Object p5 = clazz.newInstance();
        method.invoke(p5,"哈哈哈");
    }
}
